package com.sojson.project.sys.menu.controller;

import java.io.IOException;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.sojson.config.exception.TransErrorCode;
import com.sojson.constant.Lock;
import com.sojson.enums.EEnvironmentUserType;
import com.sojson.enums.EUserType;
import com.sojson.enums.core.EGeneralStatus;
import com.sojson.project.sys.menu.controller.param.verify.MenuParamVerify;
import com.sojson.project.sys.menu.entity.bo.RouterBo;
import com.sojson.project.sys.menu.entity.bo.TreeSelect;
import com.sojson.project.sys.menu.entity.dto.MenuDto;
import com.sojson.project.sys.menu.entity.po.Menu;
import com.sojson.project.sys.menu.entity.vo.MenuVo;
import com.sojson.project.sys.menu.service.MenuService;
import com.sojson.result.Result;
import com.sojson.util.RoleUtil;
import com.sojson.util.StringUtil;
import com.sojson.util.lock.CustomLock;
import com.sojson.util.lock.LockUtil;
import com.sojson.util.param.ParamUtil;
import com.sojson.util.token.TokenUtil;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;

/**
 * 菜单权限表控制器
 * 
 * @author liu
 * @date 2022-09-08
 */
@Api(tags = "菜单权限表管理")
@RestController
@RequestMapping("/sys/menu")
public class MenuController {

    @Autowired
    private MenuService menuService;

    /**
     * 单条插入
     * 
     * @param dto
     * @return
     * @throws Exception 
     */
    @PostMapping("/save")
    @PreAuthorize("@ss.hasPermi('/sys/menu/save')")
    @ApiOperation("给菜单权限表添加一条数据")
    public Result<Boolean> save(@RequestBody Menu dto) throws Exception {
        dto.insertInit();
        // 校验参数
        Result<Boolean> paramResult = MenuParamVerify.save(dto);
        // 验证不通过
        if (!paramResult.getCode().equals(TransErrorCode.SUCCESS.getCode())) {
            return paramResult;
        }

        CustomLock lock = LockUtil.lock(Lock.MENU_UPDATE);
        try {
            menuService.add(dto);
        } finally {
            if (lock != null) {
                lock.unlock();
            }
        }

        // 刷新权限
        RoleUtil.refreshPerms();
        return Result.success();
    }

    /**
     * 通过id更新
     * 
     * @param dto
     * @return
     * @throws Exception 
     */
    @PutMapping("/updateById")
    @PreAuthorize("@ss.hasPermi('/sys/menu/updateById')")
    @ApiOperation("通过id更新菜单权限表数据")
    public Result<Boolean> updateById(@RequestBody Menu dto) throws Exception {
        dto.updateInit();
        // 校验参数
        Result<Boolean> paramResult = MenuParamVerify.updateById(dto);
        // 验证不通过
        if (!paramResult.getCode().equals(TransErrorCode.SUCCESS.getCode())) {
            return paramResult;
        }

        CustomLock lock = LockUtil.lock(Lock.MENU_UPDATE);
        try {
            menuService.update(dto);
        } finally {
            if (lock != null) {
                lock.unlock();
            }
        }

        // 刷新权限
        RoleUtil.refreshPerms();
        return Result.success();
    }

    /**
     * 列表查询
     * 
     * @param dto
     * @return
     * @throws IOException 
     */
    @GetMapping("/list")
    @PreAuthorize("@ss.hasPermi('/sys/menu/list')")
    @ApiOperation(value = "查询菜单权限表数据", response = MenuVo.class)
    public Result<List<MenuVo>> list(MenuDto dto) throws IOException {
        dto.setUserId(TokenUtil.getUserId());
        List<MenuVo> menus = menuService.selectMenuList(dto);
        return Result.success(menus);
    }

    /**
     * 通过id查询
     * 
     * @param id
     * @return
     * @throws IOException 
     */
    @GetMapping("/info/{id}")
    @PreAuthorize("@ss.hasPermi('/sys/menu/info/{id}')")
    @ApiOperation(value = "通过id查询菜单权限表数据", response = MenuVo.class)
    public Result<MenuVo> info(@PathVariable String id) throws IOException {
        ParamUtil.verifyMenuIdExist(id);

        return Result.success(menuService.findById(id));
    }

    /**
     * 通过id删除
     * 
     * @param id
     * @return
     * @throws Exception 
     */
    @DeleteMapping("/remove/{id}")
    @PreAuthorize("@ss.hasPermi('/sys/menu/remove/{id}')")
    @ApiOperation("通过id集合删除菜单权限表数据")
    public Result<Boolean> remove(@PathVariable String id) throws Exception {
        ParamUtil.verifyMenuIdExist(id);

        CustomLock lock = LockUtil.lock(Lock.MENU_UPDATE);
        try {
            menuService.removeById(id);
        } finally {
            if (lock != null) {
                lock.unlock();
            }
        }

        // 刷新权限
        RoleUtil.refreshPerms();
        return Result.success();
    }

    /**
     * 通过id修改状态
     * 
     * @param dto
     * @return
     * @throws Exception 
     */
    @PutMapping("/changeStatus")
    @PreAuthorize("@ss.hasPermi('/sys/menu/changeStatus')")
    @ApiOperation("通过id修改菜单状态")
    public Result<Boolean> changeStatus(@RequestBody Menu dto) throws Exception {
        // 校验参数
        Result<Boolean> paramResult = MenuParamVerify.updateStatus(dto);
        // 验证不通过
        if (!paramResult.getCode().equals(TransErrorCode.SUCCESS.getCode())) {
            return paramResult;
        }

        // 修改状态
        CustomLock lock = LockUtil.lock(Lock.MENU_UPDATE);
        try {
            Menu menu = new Menu();
            menu.setId(dto.getId());
            menu.setStatus(dto.getStatus());
            menuService.updateStatus(menu);
        } finally {
            if (lock != null) {
                lock.unlock();
            }
        }

        // 刷新权限
        RoleUtil.refreshPerms();
        return Result.success();
    }

    /**
     * 获取路由信息
     *
     * @return 路由信息
     * @throws IOException 
     */
    @GetMapping("/getRouters")
    @PreAuthorize("@ss.login()")
    @ApiOperation(value = "获取路由信息", response = RouterBo.class)
    public Result<List<RouterBo>> getRouters() throws IOException {
        MenuDto dto = new MenuDto();
        dto.setUserId(TokenUtil.getUserId());
        dto.setEnvironment(TokenUtil.getToken().getLoginEnv());
        List<MenuVo> menus = menuService.getMenuTreeByUserId(dto);
        return Result.success(menuService.buildMenus(menus));
    }

    /**
     * 获取菜单下拉树列表
     * 
     * @param dto
     * @return
     * @throws IOException
     */
    @GetMapping("/treeselect")
    @PreAuthorize("@ss.hasPermi('/menu/treeselect')")
    @ApiOperation(value = "获取菜单下拉树列表", response = TreeSelect.class)
    public Result<List<TreeSelect>> treeselect(MenuDto dto) throws IOException {
        dto.setUserId(TokenUtil.getUserId());
        String environment = dto.getEnvironment();
        if (StringUtil.isNotBlankString(environment)) {
            EEnvironmentUserType[] values = EEnvironmentUserType.values();
            for (EEnvironmentUserType env : values) {
                if (env.getCode().equals(environment)) {
                    if (EUserType.ADMIN.getCode().equals(env.getType())) {
                        dto.setEnvironment(null);
                    }
                    break;
                }
            }
        }
        dto.setStatus(EGeneralStatus.NORMAL.getCode());
        List<MenuVo> menus = menuService.selectMenuList(dto);

        // 将菜单列表转为树的形式
        return Result.success(menuService.buildMenuTreeSelect(menus));
    }

    /**
     * 加载对应角色菜单列表树
     * 
     * @param roleId    角色ID
     * @return
     * @throws IOException 
     */
    @GetMapping(value = "/roleMenuTreeselect")
    @PreAuthorize("@ss.hasPermi('/menu/roleMenuTreeselect')")
    @ApiOperation(value = "加载对应角色菜单列表树", response = TreeSelect.class)
    public Result<Object> roleMenuTreeselect(MenuDto dto) throws IOException {
        Result<Object> success = Result.success();

        // 菜单列表
        String environment = dto.getEnvironment();
        if (StringUtil.isNotBlankString(environment)) {
            EEnvironmentUserType[] values = EEnvironmentUserType.values();
            for (EEnvironmentUserType env : values) {
                if (env.getCode().equals(environment)) {
                    if (EUserType.ADMIN.getCode().equals(env.getType())) {
                        dto.setEnvironment(null);
                    }
                    break;
                }
            }
        }
        MenuDto menuDto = new MenuDto();
        menuDto.setUserId(TokenUtil.getUserId());
        menuDto.setEnvironment(dto.getEnvironment());
        menuDto.setStatus(EGeneralStatus.NORMAL.getCode());
        List<MenuVo> menus = menuService.selectMenuList(menuDto);

        // 已经选择的ID列表
        success.put("checkedKeys", menuService.selectMenuListByRoleId(dto.getId()));

        // 将菜单列表转为树的形式
        success.put("menus", menuService.buildMenuTreeSelect(menus));
        return success;
    }

}